'use strict';

const isAsyncFunction = (fn) => {
  return Object.prototype.toString.call(fn) === '[object AsyncFunction]';
};
/**
 * 包住错误
 * @param {function} asyncHandler
 * @return {function}
 */
function wrap(asyncHandler) {
  if (asyncHandler.length <= 3) {
    return function(req, res, next) {
      if (isAsyncFunction(asyncHandler)) {
        return asyncHandler(req, res, next).catch(next);
      } else {
        return asyncHandler(req, res, next);
      }
    };
  } else {
    return function(err, req, res, next) {
      if (isAsyncFunction(asyncHandler)) {
        return asyncHandler(err, req, res, next).catch(next);
      } else {
        return asyncHandler(err, req, res, next);
      }
    };
  }
}

/**
 * 包住所有的promise function  让他们以go语言风格返回：第一个返回值 是err 第二个才是result的形式返回结果
 * @param {*} promiseFunction
 * @return {function}
 */
function clarify(promiseFunction) {
  return async function(...args) {
    try {
      let result = await promiseFunction(...args);
      return [null, result];
    } catch (exception) {
      return [exception];
    }
  };
}
/**
 * go语言返回风格的promise函数， 变回纯正的promise返回函数
 * @param {*} goStylePromiseFunction
 * @return {AsyncFunction} async Function
 */
function goStyleToPurePromiseFunction (goStylePromiseFunction) {
  return async function (...args) {
    let [exception, result] = await goStylePromiseFunction(...args);
    if (exception) {
      return Promise.reject(exception);
    }
    return Promise.resolve(result);
  };
}

/**
 * 包住一个promise的对象 让他以go语言的风格返回 错误和返回值
  
 * 缺点： 会稍微增加一点性能损耗

 * @param {Promise} promiseResult 
 */
async function promiseGoStyle (promiseResult) {
  try {
    let result = await promiseResult;
    return [null, result];
  } catch (exception) {
    return [exception];
  }
}


module.exports = {
  clarify,
  wrap,
  promiseGoStyle,
  goStyleToPurePromiseFunction,
};
